package stack_opt

import (
	"Yasuo/iface/istack_opt"
	"Yasuo/iface/iyasuo"
	"Yasuo/utils"
	"errors"
	"fmt"
)

func FactoryStop(tv string) (istack_opt.IStackOpt)  {
	switch tv {
	case "":
		return NewSubexpressionStop()
	default:
	}

	return nil
}

// 碰到 ")"立即进行计算
type SubexpressionStop struct{}

func NewSubexpressionStop() *SubexpressionStop {
	return &SubexpressionStop{}
}

// 1. 一直运算，直到碰到(操作符号，就结算进去
// 2. ) 就不入栈了
func (SubexpressionStop) InventedOpt(iys iyasuo.IYasuo) error {
	var (
		err error
		sopt string
		u *utils.Utils
	)

	u = utils.NewUtils()

	for {
		// 1. 持续计算小括号里面的
		// 碰到 = 就弹出来
		sopt = iys.GetOPT().Back().Value.(string)
		if sopt == "(" {
			// 移除之前要判断一下操作符符号
			if _, err = u.RemoveLast(iys.GetOPT()); err != nil {
				return err
			}
			break
		}

		// 最上面两个操作数计算
		// 这里面的 (1) 可以理解为操作符现在只有 ( ，在上一步就推出了，不用任何计算
		if err = u.CalcTopStack(iys.GetOPD(), iys.GetOPT()); err != nil {
			break
		}
	}

	iys.SetNext(iys.GetNext()+1)

	fmt.Println(" ) 的栈>>>>>>>>>>>>>>>>>>>>>>>>>")
	printStack(iys)

	return nil
}

// 1. 正常的stop: 注意，不是常规括号()stop
// 2. 此时常规表达式的形式 1 + 2 - 3 + 6
// 3. 栈的形式应该是操作数opd比opt操作符多一个
// 4. 全特码赶出来two, 运算one
type StopCommon struct{}

func NewStopCommon() *StopCommon {
	return &StopCommon{}
}

func (StopCommon) InventedOpt(iys iyasuo.IYasuo) error {
	var (
		u *utils.Utils
		one interface{} // float64
		fone float64
		two interface{} // float64
		ftwo float64
		opt interface{} // string
		sopt string
		result float64
		ok bool
		err error
	)

	u = utils.NewUtils()

	for {
		if ok =  u.IsEmpty(iys.GetOPT()); ok {
			// 此时操作符没有了，代表为空
			break
		}
		// 1. 取出操作符
		if opt, err = u.RemoveFront(iys.GetOPT()); err != nil {
			return err
		}
		// 2. 取出第一个操作数
		if one, err = u.RemoveFront(iys.GetOPD()); err != nil {
			return err
		}
		// 3. 取出第二个操作数
		if two, err = u.RemoveFront(iys.GetOPD()); err != nil {
			return err
		}

		// 4. 第二个操作第一个
		// 因为减法 3 -1,三先入栈，1后入栈，所以需要第二个操作第一个
		if fone, ok = one.(float64); !ok {
			fmt.Println("类型转换失败，表达式错误")
			return errors.New("类型转换失败，表达式错误")
		}
		if ftwo, ok =  two.(float64); !ok {
			fmt.Println("类型转换失败，表达式错误")
			return errors.New("类型转换失败，表达式错误")
		}
		if sopt, ok = opt.(string); !ok {
			fmt.Println("类型转换失败，表达式错误")
			return errors.New("类型转换失败，表达式错误")
		}

		// 5 .计算出的结果保存进opd
		result = u.CalcBaseLogic(fone, ftwo, sopt)
		if err = u.PushFront(iys.GetOPD(), result); err != nil {
			return err
		}
	}

	iys.SetNext(iys.GetNext() + 1)
	return nil
}

